<template>
    <FeatureTabs
      v-model="innerKey"
      :tabs="tabsBasic"
      :sticky="sticky"
      :seamless="true"
      @change="onTabChange"
      :contentMaxHeight="maxContentHeight" 
    >
    <!-- fitWindow  :fitOffset="0" -->
      <template #content="{ active }">
        <div v-if="!active"></div>
  
        <!-- 加载与错误态 -->
        <el-skeleton v-if="loadingMap[innerKey]" :rows="4" animated />
        <el-alert
          v-else-if="errorMap[innerKey]"
          type="error"
          :closable="false"
          :title="String(errorMap[innerKey])"
          class="mb12"
        />
  
        <!-- 正常渲染 -->
        <keep-alive v-if="keepAlive">
          <component
            :is="activePane?.component"
            :key="innerKey"
            v-bind="resolvedProps"
            v-on="resolvedListeners"
          />
        </keep-alive>
        <component
          v-else
          :is="activePane?.component"
          :key="innerKey"
          v-bind="resolvedProps"
          v-on="resolvedListeners"
        />
      </template>
    </FeatureTabs>
  </template>
  
  <script setup>
  import { computed, reactive, ref, watch, toRaw, isRef, unref } from 'vue'
  import FeatureTabs from './FeatureTabs.vue'
  
  /**
   * panes: [{
   *   key: string, label: string,
   *   component: Component | AsyncComponent,
   *   // 取数：三选一（或都不传）
   *   load?: (key)=> Promise<any>,                          // 切换到该面板时加载一次
   *   data?: any | Ref | Promise<any> | (()=>any|Promise),  // 直接给数据/函数/ref/Promise
   *   dataKey?: string | string[],                          // 从结果里取路径，如 'rows'
   *   // 下发给子组件
   *   propName?: string,                                    // 默认 'modelValue'
   *   props?: (data)=>object,                               // 更灵活的 props 映射
   *   listeners?: (emit)=>object                            // 事件转发，emit(evt,...)
   * }]
   */
  const props = defineProps({
    panes: { type: Array, required: true },
    modelValue: { type: [String, Number], default: undefined },
    defaultActive: { type: [String, Number], default: undefined },
    keepAlive: { type: Boolean, default: true },
    sticky: { type: Boolean, default: false },
    contentMaxHeight: { type: [Number, String], default: 520 }
  })
  const emit = defineEmits(['update:modelValue','change'])
  
  /* tabs 外观需要的简化数据 */
  const tabsBasic = computed(() => props.panes.map(p => ({ key: p.key, label: p.label })))
  
  /* 受控/非受控 */
  const innerRef = ref(props.defaultActive ?? props.panes?.[0]?.key)
  const controlled = computed(() => props.modelValue !== undefined)
  watch(() => props.modelValue, v => { if (controlled.value) innerRef.value = v })
  const innerKey = computed({
    get: () => (controlled.value ? props.modelValue : innerRef.value),
    set: v => { if (!controlled.value) innerRef.value = v; emit('update:modelValue', v) }
  })
  
  /* 每个面板的数据/加载/错误缓存 */
  const dataMap = reactive(Object.create(null))
  const loadingMap = reactive(Object.create(null))
  const errorMap = reactive(Object.create(null))
  const activePane = computed(() => props.panes.find(p => p.key === innerKey.value))
  
  /* 小工具：从对象取路径值 */
  function pluck(obj, path) {
    if (!path) return obj
    const parts = Array.isArray(path) ? path : String(path).split('.')
    return parts.reduce((acc, k) => acc?.[k], obj)
  }
  
  /* 统一解析数据源 */
  async function resolveSource(src, dataKey) {
    let val = src
    if (typeof val === 'function') val = val()
    if (isRef(val)) val = unref(val)
    if (val && typeof val.then === 'function') val = await val
    return pluck(val, dataKey)
  }
  
  /* 按需加载（优先 load，其次 data） */
  async function ensureLoaded(key) {
    const pane = props.panes.find(p => p.key === key)
    if (!pane) return
    if (dataMap[key] !== undefined || loadingMap[key]) return
  
    if (pane.load) {
      try {
        loadingMap[key] = true; errorMap[key] = null
        const res = await pane.load(key)
        dataMap[key] = pluck(res, pane.dataKey)
      } catch (e) {
        errorMap[key] = e?.message ?? e
      } finally {
        loadingMap[key] = false
      }
      return
    }
  
    if ('data' in pane) {
      if (isRef(pane.data)) {
        dataMap[key] = pluck(unref(pane.data), pane.dataKey)
        watch(pane.data, v => { dataMap[key] = pluck(v, pane.dataKey) })
        return
      }
      try {
        loadingMap[key] = true; errorMap[key] = null
        dataMap[key] = await resolveSource(pane.data, pane.dataKey)
      } catch (e) {
        errorMap[key] = e?.message ?? e
      } finally {
        loadingMap[key] = false
      }
    }
  }
  
  /* 初始化 & 切换加载 */
  watch(innerKey, k => { ensureLoaded(k) }, { immediate: true })
  
  function onTabChange(pane) { emit('change', pane) }
  
  /* 下发 props：优先 panes[i].props，其次 propName（默认 modelValue） */
  const resolvedProps = computed(() => {
    const pane = activePane.value
    const data = toRaw(dataMap[innerKey.value])
    if (!pane) return {}
    if (pane.props) return { ...pane.props(data) }
    const propName = pane.propName || 'modelValue'
    return { [propName]: data }
  })
  
  /* 事件绑定：如未自定义，默认接收 v-model 回灌容器缓存 */
  const resolvedListeners = computed(() => {
    const pane = activePane.value
    if (!pane?.listeners) {
      const propName = pane?.propName || 'modelValue'
      return { [`update:${propName}`]: (v) => { dataMap[innerKey.value] = v } }
    }
    return pane.listeners((evt, ...args) => emit(evt, ...args))
  })
  
  /* 暴露 reload 能力 */
  async function reload(key = innerKey.value) {
    if (!key) return
    dataMap[key] = undefined
    await ensureLoaded(key)
  }
  defineExpose({ reload })
  </script>
  